package com.yixun.qfbao.api.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import com.alibaba.fastjson.JSONObject;
import com.yixun.qfbao.api.service.MyService;
import com.yixun.qfbao.api.service.SaveAttetionBindInfoService;
import com.yixun.qfbao.api.service.SubscriptionApiService;
import com.yixun.qfbao.api.service.ThirdPartyApiService;
import com.yixun.qfbao.api.service.WeChatMessageService;
import com.yixun.qfbao.api.service.WeiXinService;
import com.yixun.qfbao.apidto.ChangeWeixinModelSettingReqDto;
import com.yixun.qfbao.apidto.ChangeWeixinModelSettingResDto;
import com.yixun.qfbao.apidto.GetWeiXinJsTicketReqDto;
import com.yixun.qfbao.apidto.GetWxModelSetListReqDto;
import com.yixun.qfbao.apidto.GetWxModelSetListResDto;
import com.yixun.qfbao.apidto.base.CommonReqDTO;
import com.yixun.qfbao.apidto.base.CommonResDTO;
import com.yixun.qfbao.apidto.v10dto.BaseResponseDto;
import com.yixun.qfbao.constant.WxConstant;
import com.yixun.qfbao.constant.WxMessageTemplate;
import com.yixun.qfbao.mapper.SubscriptionMapper;
import com.yixun.qfbao.mapper.WxBindMapper;
import com.yixun.qfbao.model.Company;
import com.yixun.qfbao.model.CompanyWxconfig;
import com.yixun.qfbao.model.PartnerInfo;
import com.yixun.qfbao.model.Subscription;
import com.yixun.qfbao.model.ThirdPartyUser;
import com.yixun.qfbao.model.WxBind;
import com.yixun.qfbao.model.WxmsgModel;
import com.yixun.qfbao.model.dto.CompanyDto;
import com.yixun.qfbao.model.dto.CompanyWxconfigDto;
import com.yixun.qfbao.model.dto.PartnerInfoDto;
import com.yixun.qfbao.model.dto.SubscriptionDto;
import com.yixun.qfbao.model.dto.ThirdPartyUserDto;
import com.yixun.qfbao.model.dto.WechatMessageDto;
import com.yixun.qfbao.model.dto.WxmsgModelDto;
import com.yixun.qfbao.model.enums.DelFlagEnum;
import com.yixun.qfbao.model.enums.SystemIdEnum;
import com.yixun.qfbao.model.enums.ThirdPlatEnum;
import com.yixun.qfbao.model.enums.WxConfigEnum;
import com.yixun.qfbao.service.CompanyService;
import com.yixun.qfbao.service.CompanyWxconfigService;
import com.yixun.qfbao.service.PartnerInfoService;
import com.yixun.qfbao.service.SubscriptionService;
import com.yixun.qfbao.service.ThirdPartyUserService;
import com.yixun.qfbao.service.WxmsgModelService;
import com.yixun.qfbao.util.HttpApi;
import com.yixun.qfbao.util.SSLClient;
import com.yixun.qfbao.util.StringUtil;
import com.yixun.qfbao.util.WeixinCommon;
import com.yixun.qfbao.util.WxAccessTokenCacheUtils;
import com.yixun.qfbao.util.exception.TServerException;
import com.yixun.qfbao.util.wxmsg.AesException;
import com.yixun.qfbao.xf.model.enums.ResultEnum;
import com.yixun.qfbao.xf.service.CaseMemberService;

@Service
public class WeiXinServiceImpl implements WeiXinService {
    private Logger logger = LoggerFactory.getLogger(WeiXinServiceImpl.class);
    static String wexinTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token";
    static String wexinInfoUrl = "https://api.weixin.qq.com/sns/userinfo";

    @Autowired
    private ThirdPartyUserService thirdPartyUserService;
    @Autowired
    private CompanyService companyService;
    @Autowired
    private PartnerInfoService partnerInfoService;
    @Autowired
    private ThirdPartyApiService thirdPartyApiService;
    @Autowired
    private CompanyWxconfigService companyWxconfigService;
    @Autowired
    private SubscriptionApiService subscriptionApiService;
    @Autowired
    private WxmsgModelService wxmsgModelService;
    @Autowired
    private CaseMemberService caseMemberService;
    @Autowired
    SaveAttetionBindInfoService saveAttetionBindInfoService;
    @Autowired
    private SubscriptionService subscriptionService;
    @Autowired
    com.yixun.qfbao.service.WechatMessageService wechatMessageService;
    @Resource
    WeChatMessageService msgSubscriptionService;
    @Autowired
    WxAccessTokenCacheUtils wxAccessTokenCacheUtils;
    @Autowired
	SubscriptionMapper subscriptionMapper;
    @Autowired
    WxBindMapper wxBindMapper;
    @Autowired
    MyService myService;
  
    
    /**
     * 通过code换取网页授权access_token
     * @param code
     * @param companyUuid
     * @param systemId
     * @return
     */
    public Map<String,String> getWeiXinToken(String code, String companyUuid, String systemId){

        if(systemId.equals(SystemIdEnum.DEVELOPERS.getCode())){
            systemId = SystemIdEnum.ASSISTANT.getCode();
        }else if(systemId.equals(SystemIdEnum.AGENCY_WEB.getCode())){
            systemId = SystemIdEnum.AGENCY_h5.getCode();
        }
        Subscription subscription = subscriptionApiService.getSubscriptionInfo(companyUuid, null, systemId);
        if(subscription == null) {
            return null;
        }

        StringBuilder sb = new StringBuilder("appid=");
        sb.append(subscription.getAppId());
        sb.append("&secret=");
        sb.append(subscription.getAppSecret());
        sb.append("&code=");
        sb.append(code);
        sb.append("&grant_type=authorization_code");

        String returnString = HttpApi.sendGet(wexinTokenUrl,sb.toString());
        JSONObject jsonObject = JSONObject.parseObject(returnString);
        if(Objects.isNull(jsonObject) || jsonObject.containsKey("errcode")){
            logger.info("WeiXinServiceImpl ==> getWeiXinToken error: {}", returnString);
            return null;
        }
        String token = jsonObject.getString("access_token");
        String openId = jsonObject.getString("openid");
        Map<String,String> returnMap = new HashMap<>();
        returnMap.put("token",token);
        returnMap.put("openId",openId);
        return returnMap;
    }

    public ThirdPartyUserDto getWeiXinInfo(String token,String openId){
        StringBuilder sb = new StringBuilder("?access_token=");
        sb.append(token);
        sb.append("&openid=");
        sb.append(openId);
        sb.append("&lang=zh_CN");


        String returnString = SSLClient.postSSLUrlWithParams(wexinInfoUrl + sb.toString(),null,"utf-8");
        JSONObject jsonObject = JSONObject.parseObject(returnString);

        if(jsonObject.containsKey("errcode")){
            logger.info("WeiXinServiceImpl ==> getWeiXinInfo error: {}", returnString);
            return null;
        }
        ThirdPartyUserDto thirdPartyUser = new ThirdPartyUserDto();
        thirdPartyUser.setOpenId(jsonObject.getString("openid"));
        thirdPartyUser.setNickName(jsonObject.getString("nickname"));
        thirdPartyUser.setSex(jsonObject.getInteger("sex"));
        thirdPartyUser.setProvince(jsonObject.getString("province"));
        thirdPartyUser.setCity(jsonObject.getString("city"));
        thirdPartyUser.setHeadimgurl(jsonObject.getString("headimgurl"));
        thirdPartyUser.setCountry(jsonObject.getString("country"));
        thirdPartyUser.setDelFlag(DelFlagEnum.UNDEL.getNo());
        thirdPartyUser.setPaltType(ThirdPlatEnum.WX.getCode());
        thirdPartyUserService.addNewUser(thirdPartyUser);
        return thirdPartyUser;
    }

    public BaseResponseDto<ThirdPartyUser> getUserInfoFor(String openId){
        BaseResponseDto<ThirdPartyUser> baseResponseDto = new BaseResponseDto<>();
        ThirdPartyUser thirdPartyUser = new ThirdPartyUser();
        ThirdPartyUserDto thirdPartyUserDto = new ThirdPartyUserDto();
        thirdPartyUserDto.setOpenId(openId);
        thirdPartyUserDto.setDelFlag(DelFlagEnum.UNDEL.getNo());
        List<ThirdPartyUser> list =  thirdPartyUserService.selectListByDto(thirdPartyUserDto);
        if(list == null || list.size() == 0){
            PartnerInfoDto partnerInfoDto = new PartnerInfoDto();
            partnerInfoDto.setWxOpenid(openId);
            partnerInfoDto.setDelFlag(DelFlagEnum.UNDEL.getNo());
            List<PartnerInfo> partnerInfoList =  partnerInfoService.selectListByDto(partnerInfoDto);
            if(partnerInfoList != null || partnerInfoList.size() > 0){
                thirdPartyUser.setOpenId(openId);
                thirdPartyUser.setNickName(partnerInfoList.get(0).getAccountName());
            }else{
                baseResponseDto.setResponseCode(ResultEnum.FAIL.getNo());
                return baseResponseDto;
            }
        }else{
            thirdPartyUser.setNickName(list.get(0).getNickName());
            thirdPartyUser.setOpenId(openId);
        }
        baseResponseDto.setResponseCode(ResultEnum.SUCCESS.getNo());
        baseResponseDto.setData(thirdPartyUser);
        return baseResponseDto;
    }

    @Override
    public Map getWxConfig(String companyUuid, String subDomain, String systemId) {

        Map<String,String> resultMap = new HashMap();
        //判断是否开启微信推送配置
        CompanyWxconfigDto companyWxconfig = new CompanyWxconfigDto();
        companyWxconfig.setCompanyUuid(companyUuid);
        companyWxconfig.setDomain(subDomain);
        companyWxconfig.setSystemId(systemId);
        companyWxconfig.setConfiged(WxConfigEnum.OPEN.getCode());
        companyWxconfig.setDelFlag(DelFlagEnum.UNDEL.getNo());
        CompanyWxconfig comWxconfig = companyWxconfigService.selectByDto(companyWxconfig);
        if(null == comWxconfig  || comWxconfig.getConfiged().equals(WxConfigEnum.CLOSE.getCode())) {
            resultMap.put("code", "fail");
            return resultMap;
        }

        //获取appId
        GetWeiXinJsTicketReqDto reqDto = new GetWeiXinJsTicketReqDto();
        reqDto.setCompanyUuid(companyUuid);
        reqDto.setLoginType(systemId);
        //兼容老设计
        if(StringUtils.isBlank(companyUuid)) reqDto.setDomain(subDomain);
        Map<String, String> configMap = thirdPartyApiService.getWeiXinAppid(reqDto);
        if(configMap != null && configMap.size() > 0) {
            resultMap.put("code", "success");
            resultMap.put("appId", configMap.get("appId"));
            resultMap.put("companyUuid", configMap.get("companyUuid"));
        }
        return resultMap;
    }

    @Override
    public GetWxModelSetListResDto getWxMsgModelList(GetWxModelSetListReqDto reqDto){
        GetWxModelSetListResDto resDto = new GetWxModelSetListResDto();
        //获取公司信息
        CompanyDto companyDto = new CompanyDto();
        companyDto.setDelFlag(DelFlagEnum.UNDEL.getNo());
        companyDto.setCompanyUuid(reqDto.getCompanyUuid());
        companyDto.setDomain(reqDto.getDomain());
        Company company = companyService.selectByDto(companyDto);
        if(company == null){
            throw  new TServerException("公司信息不存在");
        }
        WxmsgModelDto wxmsgModelDto = new WxmsgModelDto();
        wxmsgModelDto.setDelFlag(DelFlagEnum.UNDEL.getNo());
        wxmsgModelDto.setCompanyId(company.getId());
        wxmsgModelDto.setWxModelTypes(Arrays.asList(WxMessageTemplate.CASE_MEMBER_CONFIGURE));
        List<WxmsgModel> list = wxmsgModelService.selectListByDtoAll(wxmsgModelDto);
        if(list == null || list.size() == 0){
            resDto.setList(new ArrayList<>());
        }else{
            resDto.setList(list);
        }
        resDto.setResult(ResultEnum.SUCCESS.getNo());
        return resDto;
    }

    //修改商户的楼盘
    @Override
    public ChangeWeixinModelSettingResDto changeWexinModelSetting(ChangeWeixinModelSettingReqDto reqDto){
        ChangeWeixinModelSettingResDto resDto = new ChangeWeixinModelSettingResDto();
        resDto.setResult(ResultEnum.SUCCESS.getNo());
        if(reqDto.getChangeList() == null || reqDto.getChangeList().size() == 0){
            return  resDto;
        }
        try{
            for(WxmsgModel wm : reqDto.getChangeList()){
                //遍历修改微信模板权限
                WxmsgModelDto wxmsgModelDto = new WxmsgModelDto();
                wxmsgModelDto.setWxModelType(wm.getWxModelType());
                wxmsgModelDto.setEnabled(wm.getEnabled());
                wxmsgModelDto.setCompanyId(wm.getCompanyId());
                wxmsgModelService.updateByMsgId(wxmsgModelDto);
            }
        }catch (Exception e){
            logger.error("WeiXinServiceImpl ==> changeWexinModelSetting error: {}", e);
            resDto.setResult(ResultEnum.FAIL.getNo());
            resDto.setResultMsg("更新模板消息失败");
        }
        return resDto;
    }

    //复用短信设置
    @Override
    public CommonResDTO weixinMsgPushSetting(CommonReqDTO reqDTO){
        //获取公司信息
        CommonResDTO commonResDTO = new CommonResDTO();
        CompanyDto companyDto = new CompanyDto();
        companyDto.setCompanyUuid(reqDTO.getCompanyUuid());
        companyDto.setDomain(reqDTO.getDomain());
        companyDto.setDelFlag(DelFlagEnum.UNDEL.getNo());
        Company company = companyService.selectByDto(companyDto);
        if(company == null){
            commonResDTO.setResult(ResultEnum.FAIL.getNo());
            commonResDTO.setResultMsg("未获取公司信息");
        }else{
            commonResDTO.setResult(ResultEnum.SUCCESS.getNo());
            caseMemberService.reuseSmsSetting(company.getId());
        }
        return commonResDTO;

    }
    
    
    /**
     * 微信消息回调
     *	 1、  解析xml
     *   2、微信消息入库记录
     *	 3、  根据业务类型获取对应的消息处理类
     *	 4、  调用对应的业务处理方法
     */
    @Async
    @Override
    public void wxMsgCallBack(String appId, String msgContent) {
    	logger.info("WeiXinController->wxMsgCallBack->START");
    	//1、获取公共参数，然后添加记录至数据库
    	Map<String, String> msgMap = insertWeChatMessage(msgContent);
    	//2、获取对应的业务处理类并处理
    	String event = msgMap.get("Event");
    	String msgType = msgMap.get("MsgType");
    	WeChatMessageService weChatMessageService;
    	if(("subscribe".equals(event) || "unsubscribe".equals(event)) && "event".equals(msgType)) {
    		weChatMessageService = msgSubscriptionService;
    	}else {
    		return;
    	}
    	//获取token
		SubscriptionDto subscriptionDto = new SubscriptionDto();
		// 查找对应的app信息。
		subscriptionDto.setAppId(appId);
		subscriptionDto.setDelFlag(DelFlagEnum.UNDEL.getNo());
		List<Subscription> subscriptionList = subscriptionMapper.list(subscriptionDto, 0, 1);
		if(CollectionUtils.isEmpty(subscriptionList)) {
			logger.info("WeiXinController->wxMsgCallBack->未获取到订阅信息");
			return;
		}
		
		weChatMessageService.doBusiness(appId, msgMap, subscriptionList.get(0).getCompanyUuid(), 
				subscriptionList.get(0).getSystemId());
		return;
    }
    
    /**
     * 解析XML
     * 插入微信记录
     * @param msgContent
     * @return 返回当前的消息类型
     */
    private Map<String, String> insertWeChatMessage(String msgContent) {
    	Map<String, String> msgMap = WeixinCommon.xmlToMap(msgContent);
    	//消息转换失败，则不继续进行
    	if(msgMap == null) {
    		return null;
    	}
    	String msgType = msgMap.get("MsgType");
    	String event = msgMap.get("Event");
    	if(("subscribe".equals(event) || "unsubscribe".equals(event)) && "event".equals(msgType)) {
    		String fromUser = msgMap.get("FromUserName");
        	String toUser = msgMap.get("ToUserName");
    		WechatMessageDto wechatMessageDto = new WechatMessageDto();
        	wechatMessageDto.setContent(msgContent);
        	wechatMessageDto.setCreateTime(new Date());
        	wechatMessageDto.setFromUser(fromUser);
        	wechatMessageDto.setUpdateTime(new Date());
        	wechatMessageDto.setToUser(toUser);
        	wechatMessageDto.setContent(msgContent);
        	wechatMessageDto.setEvent(event);
        	wechatMessageDto.setMsgType(msgType);
        	wechatMessageDto.setDelFlag(DelFlagEnum.UNDEL.getNo());
        	wechatMessageService.create(wechatMessageDto);
    	}
    	return msgMap;
    }
    
    public static void main(String[] args) throws AesException {
//    	String appId = "wxd3bf8709f7c40faf";
//    	String fromXML = "<xml>    <ToUserName><![CDATA[gh_e96b293fc147]]></ToUserName>    <Encrypt><![CDATA[YW/r8/ynEXwEwEQJjBqZWFPa+xo4EYI8Y476Cp81UsWh1ZecgFGetSd6/aUEv4OwqfwV9PMrQS8vshwzj8pVOSAjQRVIPymEWCT9Jjf/lpvoBUUoQKoB3tosJQIRXSL65ZEZCsbxSQ6YC1GyjM2bUDx9mGmyrX46uHxYGUMDjecJmHlRo4bszT4WqzfQk4AK8K3lSPPCZBgTwxtGKYrYEd3ZImden/GGveuPW454xBML4hqTqBeu7F9Mdy8uVcN0IIOBx8uAAeGRQOH4X1BF6KUArl7RdIRcTfnAaAFi9CpeiAcIamxWrZbS8iF3w6c5FgB9MkQs9d9T620MAQMoFomFO2DLTHoDvoFXuhM52K8vdXgvhWgR+dhO4MDhzATmgmbtoUUTXAgXqQa3EfdynxEecLvQ/b4FIrAL6o1AfxI=]]></Encrypt></xml>";
//    	WXBizMsgCrypt pc = new WXBizMsgCrypt("channel", WxConstant.ENCODING_KEY, appId);
//    	String a = pc.decryptMsg("5393639367ab99b66af31f2099a865ea5a368bac", "1600759677", "496893459", fromXML);
//    	System.out.println(a);
    	
//    	String msgContent = "<xml><ToUserName><![CDATA[gh_e96b293fc147]]></ToUserName>\r\n" + 
//    			"<FromUserName><![CDATA[odlaI5_0_swA1Rqa9b9KqMCuv4bE]]></FromUserName>\r\n" + 
//    			"<CreateTime>1600759677</CreateTime>\r\n" + 
//    			"<MsgType><![CDATA[event]]></MsgType>\r\n" + 
//    			"<Event><![CDATA[subscribe]]></Event>\r\n" + 
//    			"<EventKey><![CDATA[]]></EventKey>\r\n" + 
//    			"</xml>";
//    	System.out.println(WeixinCommon.xmlToMap(msgContent));
	}
    
    /**
     * 刷新公众号的关注信息至绑定信息表
     * @return
     */
    @Override
    public String refreshAttetionToBindInfo(String appId) {
    	
    	//1、获取所有的appId，secret
    	List<Map<String, Object>> appIdInfoList = subscriptionService.getAllAppIdInfos(appId);
    	logger.info("WeiXinServiceImpl->refreshAttetionToBindInfo->appIdInfoList:{}", appIdInfoList);
    	
    	//已处理的appId的缓存
    	List<String> hasDealAppId = new ArrayList<>();
    	
    	//开启多个线程,使用自带的线程池进行异步处理
    	for (Map<String, Object> appIdInfo : appIdInfoList) {
    		
    		String toDealAppId = String.valueOf(appIdInfo.get("app_id"));
    		
    		//按照公众号来，所以appId一致的应该代表着已经进行关注数据刷新处理，不用继续调用处理
    		if (hasDealAppId.contains(toDealAppId)) {
    			continue;
    		}
    		
    		//预备保留入口，需要传入的appId与查询的appId一致，方可执行
    		if(StringUtils.isNotEmpty(appId)) {
    			if (!toDealAppId.equals(appId)) {
    				continue;
    			}
    		}
    		
    		//删除数据.置为-1
    		WxBind wxBind = new WxBind();
    		wxBind.setAppId(appId);
    		wxBindMapper.del(wxBind);
    		
    		//刷新数据
    		saveAttetionBindInfoService.saveAttetionBindInfo(appIdInfo);

    		hasDealAppId.add(toDealAppId);
		}
    	
    	return "success";
    }

    /**
     * 刷新人员的openId
     */
	@Override
	public String refreshOpenId(String openId, String userId, String systemId, String companyUuid) {
		
		if(!StringUtil.isNotNull(openId, userId, systemId, companyUuid)) {
			return "参数非法";
		}
		
		boolean refershFlag = judgeRefersh(systemId, companyUuid);
		
		if(refershFlag) {
			PartnerInfoDto entity = new PartnerInfoDto();
			entity.setId(Long.parseLong(userId));
			entity.setWxOpenid(openId);
			entity.setLastLoginSystemId(systemId);
			partnerInfoService.update(entity);
			logger.info("更新成功");
			return "succ";
		}
		logger.info("未开启更新");
		return "未开启更新";
	}
	
	
	private boolean judgeRefersh(String systemId, String companyUuid) {
		return myService.enableWeappMsg(systemId, companyUuid);
	}
	
	/**
	 * 获取当前公司对应内容的小程序码
	 * 注意40001的补偿
	 * @param accessToken
	 * @param scene
	 * @param page
	 * @return
	 */
	@Override
	public byte[] getWeappQrCodeByCompanyUuid(String CompanyUuid, String scene, String page) {
		// 1、获取对应的accessToken
		String accessToken = wxAccessTokenCacheUtils.getAccessTokenBySystemId(CompanyUuid, 
				SystemIdEnum.WEAPP_AGENCY.getCode(), null);
		byte[] weappQrCode = getWeappQrCode(accessToken, scene, page);
		return weappQrCode;
	}
	
	/**
	 * 	获取分销小程序二维码
	 * @param accessToken
	 * @param scene
	 * @param page
	 * @return
	 */
	private byte[] getWeappQrCode(String accessToken, String scene, String page) {
		JSONObject param = buildWeappQrCodeParam(scene, page);
		String url = WxConstant.GET_UNLIMITED.replace("ACCESS_TOKEN", accessToken);
		byte[] entity = HttpApi.doPostForEntity(url, param.toJSONString());
		return entity;
	}
	
	/**
	 * 构建生成小程序码调用的入参
	 * @param accessToken
	 * @param scene
	 * @param page
	 * @return
	 */
	private JSONObject buildWeappQrCodeParam(String scene, String page){
		JSONObject param = new JSONObject();
//		param.put("accessToken", accessToken);
		param.put("scene", scene);
		param.put("page", page);
		return param;
	}
}
